iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 25
0
Modern Web

NestJs 讀書筆記系列 第 25

實戰 - 前端實作篇

  • 分享至 

  • xImage
  •  

前端實作篇

我將 TodoTask 跟 DoneTask 個別獨立成 Component
在由 Task.vue 引入 Component,以下便是 template 內容

<template>
    <div class="task">
        <TodoTask />
        <DoneTask />
            
        <v-fab-transition>
            <v-btn>
                <v-icon>mdi-plus</v-icon>
            </v-btn>
        </v-fab-transition>
        <v-dialog></v-dialog>
    </div>
</template>

TodoTask 跟 DoneTask 的作法基本上一樣,所以直接說明其中一個的做法
直接使用 vuetify 提供的 v-list 當最主元件
每一筆 Task 都由 v-list-item 呈現

我的設計是,當 List 超出版面時就能 Scroll ,滾軸滑到底時就會觸發事件並載入後續的資料
這邊的事件觸發使用 vuetify 提供的 Intersection Observer API ,當滾軸滑到最後一筆時,v-intersect 就會被觸發,接著在判斷是否要仔入資料或是要載入哪些資料
最後再將取得的資料存入 vue apollo 的緩存中,畫面也會渲染成最新的資料

DoneTask

以 DoneTask 來說
當滾軸滑到底需要載入新資料時,用 $emit 傳遞事件給父層 Task.vue ,由父層實作
取得新資料後再經由 Prop 將資料傳給子層 DoneTask.vue
這樣就能更新 DoneTask 的資料

<v-list two-line>
    <v-subheader>DONE</v-subheader>
    <v-divider></v-divider>
    <v-list-item-group v-if="doneTasks">
        <template v-for="(task, index) in doneTasks.tasks" >
            <v-list-item v-if="doneTasks.tasks.length - 1 > index" :key="task.id" >
                <v-list-item-content>
                    <v-list-item-title>{{task.title}}</v-list-item-title>
                    <v-list-item-subtitle>{{task.content}}</v-list-item-subtitle>
                </v-list-item-content>
                <v-list-item-action>
                    <v-icon color="green lighten-1">mdi-check</v-icon>
                </v-list-item-action>
            </v-list-item>

            <v-list-item v-else :key="task.id" v-intersect="loadDataDoneTask" >
                <v-list-item-content>
                    <v-list-item-title>{{task.title}}</v-list-item-title>
                    <v-list-item-subtitle>{{task.content}}</v-list-item-subtitle>
                </v-list-item-content>
                <v-list-item-action>
                    <v-icon color="green lighten-1">mdi-check</v-icon>
                </v-list-item-action>
            </v-list-item>
        </template>
    </v-list-item-group>
</v-list>
<script>
export default {
    props: ['doneTasks'],
    methods: {
        loadDataDoneTask(entries, observer, isIntersecting) {
            if (!isIntersecting) return;
            if (this.doneTasks.taskCount == 0 || this.doneTasks.tasks.length === this.doneTasks.taskCount) return;

            this.$emit('loadDataDoneTask');
        }
     }
}
</script>

在 Task.vue 的實作
vue apollo 的 Smart Query 提供 fetchMore 的方法,主要目的就是做分頁
在 updateQuery 中能取得未更新的資料以及呼叫分頁資料回來的結果
做一些邏輯運算後,將結果回傳給緩存,這樣就成功更新緩存裡的資料

loadDataDoneTask() {
    const currentPageCount = this.doneTaskArgs.pageSize * this.doneTaskArgs.page;

    this.doneTaskArgs.start = currentPageCount + this.doneTaskArgs.pageSize;
    this.$apollo.queries.doneTasks.fetchMore({
        // New variables
        variables: this.doneTaskArgs,
        // Transform the previous result with new data
        updateQuery: (previousResult, { fetchMoreResult, variables }) => {
            previousResult.doneTasks.tasks.push(...fetchMoreResult.doneTasks.tasks);
            previousResult.doneTasks.taskCount = fetchMoreResult.doneTasks.taskCount;

            return {
                doneTasks: previousResult.doneTasks
            }
        },
    })

    this.doneTaskArgs.page ++;
}

Add Task

接下來是新增的部分
流程是發送 API 後要更新 TodoTask ,由於不能確定新增的 Task 是目前資料的下一筆,所以沒辦法直接將 Task Push 到 todoTasks 中
透過 Smart Query 的方法 refetch 能夠手動呼叫 API ,這樣便能取得最新前 10 筆資料
雖然這樣做會讓資料一直重撈前 10 筆,但我認為這樣能簡化複雜的流程,所以選擇了這個折衷的辦法

createTask() {
    this.$apollo.mutate({
        mutation: CREATE_TASK,
        variables: {
            taskData: this.newTask
        },
        update: () => {
            this.addTaskDialog = false;
            this.$apollo.queries.todoTasks.refetch()
            Object.assign(this.todoTaskArgs, this.initPageArgs);

            this.newTask = {
                title: null,
                content: null
            }
        }
    })
}

Update Task

作法與新增 Task 一樣,只是多了更新 DoneTask

async updateTask(data) {
    await this.$apollo.mutate({
        mutation: UPDATE_TASK,
        variables: data
    })
    this.$apollo.queries.todoTasks.refetch()
    this.$apollo.queries.doneTasks.refetch()

    Object.assign(this.doneTaskArgs, this.initPageArgs);
    Object.assign(this.todoTaskArgs, this.initPageArgs);
},

以上功能都完成,我們的 Todo List 也就完成了!!! /images/emoticon/emoticon07.gif
非常簡單的一個小小專案,但是使用到的功能應該也算蠻齊全了,往後你也能跟別人說你是全端(半殘)工程師了


上一篇
實戰 - 前端切版
下一篇
NestJs 延伸篇 - Federation 介紹
系列文
NestJs 讀書筆記31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言